package com.dev.cmielke.gui.controller;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.util.Observable;
import java.util.Observer;
import java.util.TreeSet;

import javax.swing.JFileChooser;

import org.apache.log4j.Logger;

import com.dev.cmielke.generator.PDFTextExtractor;
import com.dev.cmielke.gui.beans.DocumentList;
import com.dev.cmielke.gui.command.ActionCommand;
import com.dev.cmielke.gui.command.NotifyCommand;
import com.dev.cmielke.gui.view.MainWindow;
import com.dev.cmielke.util.ApplicationContants;
import com.dev.cmielke.util.FileSystemUtils;
import com.dev.cmielke.util.filter.PortableDocumentFilter;

public class MainController implements ActionListener, Observer, ApplicationContants {
	private static Logger log = Logger.getLogger(MainController.class);

	private DocumentList list;
	private MainWindow window;

	public MainController(MainWindow window) {
		this.window = window;

		list = new DocumentList();
		list.addObserver(this);

		setWindowPrefenrences();
	}

	private void setWindowPrefenrences() {
		window.registerActionListener(this);
		window.centerWindow();
		window.setVisible(true);
	}

	public void actionPerformed(ActionEvent e) {
		ActionCommand cmd = ActionCommand.getCommand(e.getActionCommand());
		if (cmd != null) {
			switch (cmd) {
			case ADD_DOCUMENT: {
				log.debug("> ACTION: [" + cmd.name() + "," + cmd.getCode() + "]");
				JFileChooser chooser = new JFileChooser();
				chooser.setMultiSelectionEnabled(true);
				chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
				chooser.setFileFilter(new PortableDocumentFilter());
				int result = chooser.showOpenDialog(window);
				if (result == JFileChooser.APPROVE_OPTION) {
					list.addDocuments(chooser.getSelectedFiles());
				} else {
					log.debug("No files selected, dialog aborted.");
				}
				log.debug("< ACTION: [" + cmd.name() + "," + cmd.getCode() + "]");
				break;
			}
			case CLEAR_LIST:
				log.debug("> ACTION: [" + cmd.name() + "," + cmd.getCode() + "]");
				list.removeAllDocuments();
				log.debug("< ACTION: [" + cmd.name() + "," + cmd.getCode() + "]");
				break;
			case START_PROCESSING:
				log.debug("> ACTION: [" + cmd.name() + "," + cmd.getCode() + "]");
				
				this.window.setWorkInProgress(true);
				Converter c = new Converter();
				c.start();
				log.debug("< ACTION: [" + cmd.name() + "," + cmd.getCode() + "]");
				break;
			}
		} else {
			log.error("Could not parse ActionCommand Object!");
		}
	}

	public void update(Observable o, Object arg) {
		try {
			NotifyCommand cmd = (NotifyCommand) arg;
			switch (cmd) {
			case UPDATE_DOCUMENT_LIST: {
				log.debug("Notify-Command:[" + NotifyCommand.UPDATE_DOCUMENT_LIST.getCode() + ", value:"
						+ NotifyCommand.UPDATE_DOCUMENT_LIST.name() + "]");
				window.updateDocumentList(list.getDocumentNames());
				break;
			}
			}
		} catch (Exception e) {
			log.error("got an exception!", e);
		}
	}
	
	private class Converter extends Thread {
		public void run() {
			int convertCount=0;
			int errorCount=0;
			TreeSet<File> converterList = new TreeSet<File>(list.getFiles());
			for (File file : converterList) {
				log.info("Processing PDF-File: [" + file.getName() + "]");
				try {
					PDFTextExtractor reader = new PDFTextExtractor(file);
					reader.processDocument();
					log.trace("Deleting directory [" + OUTPUT_DIRECTORY + "]");
					try {
						FileSystemUtils.waitForDeletion();
						FileSystemUtils.cleanOutputDirectory();
						log.debug("Deletion complete!");
						convertCount++;
					} catch (IOException e) {
						log.error("Could not delete directory [" + OUTPUT_DIRECTORY + "]", e);
						log.error("Terminating Application!");
						break;
					}
					log.info("PDF converted ["+file.getName()+"]");
					list.removeDocument(file);
				}catch(Exception e) {
					log.error("PDF convert failed ["+file.getName()+"]");
					errorCount++;
				}
			}
			log.info("Convertion complete "+convertCount+" converted "+errorCount+" failures");
			MainController.this.window.setWorkInProgress(false);
		}
	}
}
